iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
0
自我挑戰組

不用前端框架 手把手打造基礎SPA網站系列 第 19

[DAY19]進階應用 - 元件內部State的應用

  • 分享至 

  • xImage
  •  

什麼是State

當我們在設計某些功能時,會需要把值暫時保存起來並存至變數供日後使用,state就像component裡的變數,當UI要顯示某個state,就可以取用當下紀錄的狀態,要使用時調出變數再進行渲染至UI。首先一樣用React當例子,來看看React對state的定義:

State 類似於 prop,但它是私有且由 component 完全控制的。

props是外部傳遞至元件內部的參數(含元件預設參數與從外部設定的變數),是無法改變的,而state是元件自己本身內部的狀態變數,是可以改變的,我們今天要看的是state。React在類別型元件設定state可以透過Class裡定義初始值後用this調用,或是透過函式型元件React Hooks的setState方法定義後從useState調用。那麼我們要怎麼在SPA裡實現類似方法呢?

State應用情境

再來回顧昨天實做彈出視窗的例子:

Home顯示的彈出視窗在每次切換頁面都會重複出現,如此會造成很差的使用體驗,可以想像在一般逛網站時,若每造訪一次頁面就跳出廣告,使用者有很大的機率會直接離開網站,所以正常狀況只有在第一次進入頁面會顯示彈出視窗,之後就不太會再次出現。

如何設置State

既然昨天我們可以在Component裡新增mount的方法執行DOM載入完成的callback,代表也可以用同樣的方式新增一個state屬性,來紀錄元件內的狀態值:

src/pages/Home.js

export const Home = {
  state: {
    //預設顯示狀態
    show: true,
  },
  mount: function () {
  //...

這裡可以看到在元件的state屬性賦予物件型別,為了要判斷是否已經顯示過彈出視窗,這裡在定義一個show的屬性,並給予布林值的true,代表預設情況下會顯示彈出視窗。

仔細了解state物件裡的配置:

  • key:屬性的名稱,名稱可以自己定義,注意避開保留字。
  • value:可以是任何值,凡string/number/boolean/function/array/object/promise等皆可。

如何使用State

我們剛剛已經設置好Component內的state,接下來可以看看如何使用:

export const Home = {
  state: {
    //預設顯示狀態
    show: true,
  },
  mount: function () {
    if (this.state.show === true) {
      //呼叫modal
      $('#modal').modal('show')
    }
    //寫入狀態
    this.state.show = false
  },
  render: () => {

為了使用this調用全物件及子層屬性,在mount屬性裡使用function取代arrow function。首先使用if判斷show狀態是否顯示彈出視窗,若是true才會執行呼叫視窗的方法(預設值設定為true)。if判斷完畢後面統一設置show的顯示狀態為false,代表之後讀取Home頁面就不會再次彈出視窗了。

成果一覽:

小結

順利執行,可以看到執行第一次彈出視窗後,回到Home頁面不會再次跳出視窗,不過仔細想一想,一開始在state裡定義初始值,切換頁面後state卻可以保留設定後的狀態,這是為什麼呢? 這是因為賦予state的型別為物件,利用Javascript對物件的動態操作,在state裡新增屬性與賦值,而在切換頁面時造成hashchange事件並觸發Router,Router找到對應的Component物件後,再從Component裡調用屬性,所以切換頁面不會影響state裡的狀態。那如果每次切換頁面希望state可以回復到預設值呢?其實在mount裡對state重新進行設定就好啦!以上是今天的內容,我們明天見!

參考資料:
[React學習筆記] 暸解狀態 state 與 setState


上一篇
[DAY18]進階應用 - SPA簡易生命週期實現
下一篇
[DAY20]進階應用 - 監聽事件的處理(上篇)
系列文
不用前端框架 手把手打造基礎SPA網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言